パイプラインのステップを 1 つに合成する
from Implementation: Composing a Pipeline
LT;DR
各ステップを合成する際に、入力と出力の型が異なる問題によく出くわす
これを解決するには 部分適用 を利用する
パイプラインのステップを 1 つに合成する#66a9e34375d04f0000fca83a
https://scrapbox.io/files/66a9e4ce93b181001d498f16.png
依存関係 を注入する方法については、DMMF: 依存関係の注入 を参照
部分適用 を適用しても解決できない場合、関数アダプタ の作成や 命令型 っぽく書くことで解決できる
パイプラインのステップを 1 つに合成する#66a9e56175d04f0000fca858
hr.icon
最初のステップの実装 と 残りのステップの実装 で実装したステップを 1 つに合成する
イメージ
code:fsharp
let placeOrder: PlaceOrderWorkflow =
fun unvalidatedOrder ->
|> validateOrder
|> priceOrder
|> acknowledgeOrder
|> createEvents
問題点
validateOrder には 依存関係 の余計な入力が 2 つあるため、入力と出力が一致しない
https://scrapbox.io/files/66a9e2f24f5917001c1cb168.png
priceOrder も同様に、余計な入力があるため一致しない
https://scrapbox.io/files/66a9e34059ddca001c21c2ba.png
「形」の異なる関数を合成することは、FP における主要な課題の 1 つ
DMMF: 関数合成#66a3681375d04f00007fb0b8
どう解決するか?
モナド
部分適用
ものとしての関数#66a3582575d04f00007fb01f
依存関係に関するパラメータだけを適用し、入力が 1 つだけの関数を作成する
https://scrapbox.io/files/66a9e4ce93b181001d498f16.png
F# は シャドーイング が可能
code:fsharp
let validateOrder =
validateOrder checkProductCodeExists checkAddressExists
Haskell でよく見るように 末尾に ' を付けても良い
code:fsharp
let validateOrder' =
validateOrder checkProductCodeExists checkAddressExists
ワークフロー 全体
code:fsharp
let placeOrder: PlaceOrderWorkflow =
let validateOrder =
validateOrder checkProductCodeExists checkAddressExists
let priceOrder =
priceOrder getProductPrice
let acknowledgeOrder =
acknowledgeOrder createOrderAcknowledgmentLetter sendOrderAcknowledgment
fun unvalidatedOrder ->
unvalidatedOrder
|> validateOrder
|> priceOrder
// しかし、ここらへんでエラーが起きる…
|> acknowledgeOrder
|> createEvents
まだ解決できない問題がある
acknowledgeOrder の出力はイベントであり、createEvents の入力と合致しない
関数アダプタ を書いたり、命令型 っぽく書けば良い
命令型 っぽく書けば良い
明示的に各ステップの出力を変数に 束縛 する
code:fsharp
let placeOrder: PlaceOrderWorkflow =
fun unvalidatedOrder ->
let validatedOrder =
unvalidatedOrder
|> validateOrder checkProductCodeExists checkAddressExists
let priceOrder =
validatedOrder
|> priceOrder getProductPrice
let acknowledgmentOption =
priceOrder
|> acknowledgeOrder
createOrderAcknowledgmentLetter
sendOrderAcknowledgment
let events =
createEvents acknowledgmentOption events
events